package ThreadSafety;

public class PrintABC {
    public volatile static int flag = 0;
    public static void main(String[] args) {
        Object locker = new Object();
        Thread a = new Thread(() -> {
            synchronized (locker) {
                for (int i = 0; i < 10; i++) {//1》执行次数
                    while(flag!=0) {//2》满足执行次数的前提下还要保证，线程wait时，不能跳出执行次数的限制，所以使用while而不是if else判断
                        try {
                            locker.wait();
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    }
                    System.out.print("A");
                    flag = 1;
                    locker.notifyAll();
                }
            }
        });

        //关键要点：每个线程的for (int i = 0; i < 10; i++)定义了 “必须执行 10 次打印” 的目标。
        //但线程在执行过程中可能因条件不满足而wait()，如果用if判断，一旦发生虚假唤醒（没被正确唤醒却醒来了），线程会直接跳过wait()，进入下一次for循环，导致 “该执行的打印没执行，却消耗了一次循环计数”，最终打印次数不足 10 次。
        //用while循环时，即使虚假唤醒，线程也会重新检查条件：如果条件不满足，会继续wait()，不会提前消耗for循环的计数，直到条件正确时才执行打印并让i自增，从而严格保证 10 次循环都有效执行。

        Thread b = new Thread(() -> {
            synchronized (locker) {
                for (int i = 0; i < 10; i++) {
                    while(flag!=1) {
                        try {
                            locker.wait();
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    }
                    System.out.print("B");
                    flag = 2;
                    locker.notifyAll();
                }
            }
        });

        Thread c = new Thread(() -> {
            synchronized (locker) {
                for (int i = 0; i < 10; i++) {
                    while(flag!=2) {
                        try {
                            locker.wait();
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    }
                    System.out.print("C");
                    System.out.println();
                    flag=0;
                    locker.notifyAll();
                }
            }
        });

        a.start();
        b.start();
        c.start();
    }
}
